home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / Xconq 7.0d16 / Xconq 7.0d16 src / mac / macdraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-06  |  22.0 KB  |  850 lines  |  [TEXT/KAHL]

  1. /* Copyright (c) 1992, 1993  Stanley T. Shebs. */
  2. /* This program may be used, copied, modified, and redistributed freely */
  3. /* for noncommercial purposes, so long as this notice remains intact. */
  4.  
  5. /* Picture drawing for the Mac interface. */
  6.  
  7. #include "conq.h"
  8. #include "mac.h"
  9.  
  10. #include <Sound.h>
  11.  
  12. #define move_cell_region(sx, sy, power)  \
  13.   OffsetRgn(cellrgns[power], sx - lastcellrgnx[power], sy - lastcellrgny[power]);  \
  14.   lastcellrgnx[power] = sx;  lastcellrgny[power] = sy;  \
  15.   OffsetRgn(gridcellrgns[power], sx - lastgridcellrgnx[power], sy - lastgridcellrgny[power]);  \
  16.   lastgridcellrgnx[power] = sx;  lastgridcellrgny[power] = sy;
  17.  
  18. extern BitMap bordbitmaps[];
  19. extern BitMap connbitmaps[];
  20.  
  21. PolyHandle polygons[NUMPOWERS];
  22. int lastpolyx[NUMPOWERS], lastpolyy[NUMPOWERS];
  23.  
  24. RgnHandle cellrgns[NUMPOWERS];
  25. int lastcellrgnx[NUMPOWERS], lastcellrgny[NUMPOWERS];
  26. RgnHandle gridcellrgns[NUMPOWERS];
  27. int lastgridcellrgnx[NUMPOWERS], lastgridcellrgny[NUMPOWERS];
  28.  
  29. Image **bestterrainimages = NULL;
  30.  
  31. int numwindsicns = 0;
  32.  
  33. Handle windsicnhandle[5];
  34.  
  35. /* Draw an image of the given type of unit in the given rectangle, possibly adding
  36.    an emblem if requested. */
  37.  
  38. void
  39. draw_unit_image(win, sx, sy, sw, sh, u, e, mod)
  40. WindowPtr win;
  41. int sx, sy, sw, sh, u, e, mod;
  42. {
  43.     int ex, ey, ew, eh;
  44.     Rect srcrect, imagerect;
  45.     RgnHandle tmprgn;
  46.     BitMap bm, *winbits;
  47.     Image *uimg;
  48.  
  49.     imagerect = win->portRect;
  50.     imagerect.top += sy;  imagerect.left += sx;
  51.     imagerect.bottom = imagerect.top + sh;  imagerect.right = imagerect.left + sw;
  52.     /* Filter out very small images. */
  53.     if (sw <= 1) return;
  54.     if (sw <= 4) {
  55.         /* (should draw in a distinctive color if one is available) */
  56.         FillRect(&imagerect, QD(black));
  57.         return;
  58.     }
  59.     uimg = best_image(&(uimages[u]), sw, sh);
  60.     /* There should always be *some* image to display. */
  61.     if (uimg) {
  62.         winbits = &(((GrafPtr) win)->portBits);
  63.         if (uimg->monopict != nil) {
  64.             DrawPicture(uimg->monopict, &imagerect);
  65.         } else if (uimg->colricon != nil
  66.                    && (minscreendepth > 1
  67.                           || (uimg->monoicon == nil && uimg->monosicn == nil))) {
  68.             PlotCIcon(&imagerect, (CIconHandle) uimg->colricon);
  69.         } else if (uimg->monoicon != nil) {
  70.             SetRect(&srcrect, 0, 0, 32, 32);
  71.             bm.rowBytes = 4;
  72.             bm.bounds = srcrect;
  73.             if (uimg->maskicon != nil) {
  74.                 bm.baseAddr = *(uimg->maskicon);
  75.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  76.             } else {
  77.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  78.                 FillRect(&imagerect, QD(white));
  79.             }
  80.             bm.baseAddr = *(uimg->monoicon);
  81.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  82.         } else if (uimg->monosicn != nil) {
  83.             SetRect(&srcrect, 0, 0, 16, 16);
  84.             if (sw > 64) {
  85.                 InsetRect(&imagerect, sw / 4, sh / 4);
  86.             }
  87.             bm.rowBytes = 2;
  88.             bm.bounds = srcrect;
  89.             if (uimg->masksicn != nil) {
  90.                 bm.baseAddr = *(uimg->masksicn);
  91.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  92.             } else {
  93.                 /* Draw unit bbox as default mask. (maybe shrink a little??) */
  94.                 FillRect(&imagerect, QD(white));
  95.             }
  96.             bm.baseAddr = *(uimg->monosicn);
  97.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  98.         } else {
  99.             run_warning("Image with no content?");
  100.         }
  101.     } else {
  102.         FillRect(&imagerect, QD(black));
  103.     }
  104.     if (mod != 0) {
  105.         gray_out_rect(&imagerect);
  106.     }
  107.     /* Now draw a side emblem if asked for. */
  108.     if (between(0, e, numsides)) {
  109.         if (uimg &&
  110.             uimg->embedname &&
  111.             side_n(e) &&
  112.             side_n(e)->emblemname &&
  113.             strcmp(uimg->embedname, side_n(e)->emblemname) == 0) {
  114.             /* Correct emblem is part of the unit's image, don't need to draw. */
  115.         } else {
  116.             /* Get the size of the emblem, either from the image or by computing
  117.                a reasonable default. */
  118.             if (uimg && uimg->embedw > 0 && uimg->embedh > 0) {
  119.                 ew = uimg->embedw;  eh = uimg->embedh;
  120.             } else {
  121.                 ew = min(sw, max(8, sw / 4));  eh = min(sh, max(8, sh / 4));
  122.             }
  123.             /* Position the emblem, either explicitly, or default to UR corner
  124.                (note that we need the emblem's width to do this) */
  125.             if (uimg && uimg->embedx >= 0 && uimg->embedy >= 0) {
  126.                 ex = uimg->embedx;  ey = uimg->embedy;
  127.             } else {
  128.                 ex = sw - ew;  ey = 0;
  129.             }
  130.             /* Do the drawing proper. */
  131.             draw_side_emblem(win, sx + ex, sy + ey, ew, eh, e);
  132.         }
  133.     }
  134. }
  135.  
  136. /* Draw a given side id's emblem. Uses the current GrafPort. */
  137.  
  138. void
  139. draw_side_emblem(win, ex, ey, ew, eh, e)
  140. WindowPtr win;
  141. int ex, ey, ew, eh, e;
  142. {
  143.     int actualw, actualh;
  144.     Rect srcrect, imagerect = win->portRect;
  145.     RgnHandle tmprgn;
  146.     BitMap bm, *winbits;
  147.     Image *eimg;
  148.  
  149.     /* Filter out very small images. */
  150.     if (ew <= 1) return;
  151.     if (ew <= 2) {
  152.         /* (should draw in a distinctive color if one is available) */
  153.         /* FillRect(&imagerect, QD(black)); */
  154.         return;
  155.     }
  156.     eimg = best_image(&(eimages[e]), ew, eh);
  157.     imagerect.top += ey;  imagerect.left += ex;
  158.     actualw = eimg->w;  actualh = eimg->h;
  159.     if (ew >= actualw * 2 && eh >= actualh * 2) { actualw *= 2;  actualh *= 2; }
  160.     if (ew >= actualw * 2 && eh >= actualh * 2) { actualw *= 2;  actualh *= 2; }
  161.     if (actualw < ew) ew = actualw;
  162.     if (actualh < eh) eh = actualh;
  163.     imagerect.bottom = imagerect.top + eh;  imagerect.right = imagerect.left + ew;
  164.     /* If an image is available, display it, otherwise do nothing. */
  165.     if (eimg) {
  166.         winbits = &(((GrafPtr) win)->portBits);
  167.         if (eimg->monopict != nil) {
  168.             DrawPicture(eimg->monopict, &imagerect);
  169.         } else if (eimg->colricon != nil
  170.                    && (minscreendepth > 1
  171.                           || (eimg->monoicon == nil && eimg->monosicn == nil))) {
  172.             PlotCIcon(&imagerect, (CIconHandle) eimg->colricon);
  173.         } else if (eimg->monoicon != nil) {
  174.             SetRect(&srcrect, 0, 0, 32, 32);
  175.             bm.rowBytes = 4;
  176.             bm.bounds = srcrect;
  177.             if (eimg->maskicon != nil) {
  178.                 bm.baseAddr = *(eimg->maskicon);
  179.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  180.             } else {
  181.                 /* Use emblem bbox as default mask. */
  182.                 FillRect(&imagerect, QD(white));
  183.             }
  184.             bm.baseAddr = *(eimg->monoicon);
  185.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  186.         } else if (eimg->monosicn != nil) {
  187.             SetRect(&srcrect, 0, 0, 16, 16);
  188.             bm.rowBytes = 2;
  189.             bm.bounds = srcrect;
  190.             if (eimg->masksicn != nil) {
  191.                 bm.baseAddr = *(eimg->masksicn);
  192.                 CopyBits(&bm, winbits, &srcrect, &imagerect, srcBic, nil);
  193.             } else {
  194.                 /* Use emblem bbox as default mask. */
  195.                 FillRect(&imagerect, QD(white));
  196.             }
  197.             bm.baseAddr = *(eimg->monosicn);
  198.             CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  199.         } else {
  200.             run_warning("Image with no content?");
  201.         }
  202.     }
  203. }
  204.  
  205. draw_hex_block(sx, sy, n, power, t, t2)
  206. int sx, sy, n, power, t, t2;
  207. {
  208.     Rect rect;
  209.     Image *timg;
  210.     RGBColor hexcolor, oldcolor;                
  211.  
  212.     rect.left = sx;  rect.top = sy;
  213.     rect.right = rect.left + n * hws[power];  rect.bottom = rect.top + hcs[power];
  214.     if (bestterrainimages == NULL) {
  215.         calc_best_terrain_images();
  216.     }
  217.     timg = bestterrainimages[power * numttypes + t];
  218.     if (timg) {
  219.         if (hasColorQD) {
  220.             if (timg->colrpat != nil
  221.                 && (minscreendepth > 1 || !timg->patdefined)) {
  222.                 FillCRect(&rect, timg->colrpat);
  223.             } else if (tcolors[t] != NULL && minscreendepth > 1) {
  224.                 hexcolor.red   = (tcolors[t]->r) << 8;
  225.                 hexcolor.green = (tcolors[t]->g) << 8;
  226.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  227.                 RGBForeColor(&hexcolor);
  228.                 PaintRect(&rect);
  229.                 /* Restore the previous color. */
  230.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  231.                 RGBForeColor(&oldcolor);
  232.             } else if (timg->patdefined) {
  233. #ifdef THINK_C
  234.                 FillRect(&rect, (Pattern *) &(timg->pat));
  235. #endif
  236.             }
  237.         } else {
  238. #ifdef THINK_C
  239.             FillRect(&rect, (Pattern *) &(timg->pat));
  240. #endif
  241.         }
  242.         if (t2 == -1) {
  243.             PenPat(QD(gray));
  244. /*            PenMode(patBic);  */
  245.             PenMode(notPatOr);
  246.             PaintRect(&rect);
  247.             PenNormal();
  248.         }
  249.     }
  250. }
  251.  
  252. calc_best_terrain_images()
  253. {
  254.     int p, t;
  255.  
  256.     bestterrainimages = (Image **) xmalloc(NUMPOWERS * numttypes * sizeof(Image *));
  257.     for_all_terrain_types(t) {
  258.         for (p = 0; p < NUMPOWERS; ++p) {
  259.             bestterrainimages[p * numttypes + t] = 
  260.                 best_image(&(timages[t]), hws[p], hcs[p]);
  261.         }
  262.     }
  263. }
  264.  
  265. /* Do the grody work of drawing very large polygons accurately.  Do this by calculating
  266.    the hex polygon only once (when first needed), then offsetting each time to draw. */
  267.  
  268. draw_hex_polygon(sx, sy, power, dogrid, t, t2)
  269. int sx, sy, power, dogrid, t, t2;
  270. {
  271.     int hw = hws[power], hh = hhs[power], delt = (hhs[power] - hcs[power]);
  272.     int nw = 0, se = 0;
  273.     PolyHandle poly;
  274.     Image *timg;
  275.     RGBColor hexcolor, oldcolor;
  276.  
  277.     poly = polygons[power];
  278.     if (poly == nil) {
  279.         poly = OpenPoly();
  280.         if (hw != 20) {        
  281.             MoveTo(hw / 2, nw);
  282.             LineTo(hw - se, delt);
  283.             LineTo(hw - se, hh - delt);
  284.             LineTo(hw / 2, hh - se);
  285.             LineTo(0 + nw, hh - delt);
  286.             LineTo(0 + nw, delt);
  287.             LineTo(hw / 2, nw);
  288.         } else {
  289.             MoveTo(10, 0);
  290.             LineTo(20 - se, 5);
  291.             LineTo(20 - se, 17);
  292.             LineTo(10, 22 - se);
  293.             LineTo(0, 17);
  294.             LineTo(0, 5);
  295.             LineTo(10, 0);
  296.         }
  297.         ClosePoly();
  298.         polygons[power] = poly;
  299.         lastpolyx[power] = lastpolyy[power] = 0;
  300.     }
  301.     OffsetPoly(poly, sx - lastpolyx[power], sy - lastpolyy[power]);
  302.     lastpolyx[power] = sx;  lastpolyy[power] = sy;
  303.     if (bestterrainimages == NULL) {
  304.         calc_best_terrain_images();
  305.     }
  306.     timg = bestterrainimages[power * numttypes + t];
  307.     if (timg) {
  308.         if (hasColorQD) {
  309.             if (timg->colrpat != nil
  310.                 && (minscreendepth > 1 || !timg->patdefined)) {
  311.                 FillCPoly(poly, timg->colrpat);
  312.             } else if (tcolors[t] != NULL && maxscreendepth > 1) {
  313.                 hexcolor.red   = (tcolors[t]->r) << 8;
  314.                 hexcolor.green = (tcolors[t]->g) << 8;
  315.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  316.                 RGBForeColor(&hexcolor);
  317.                 PaintPoly(poly);
  318.                 /* Restore the previous color. */
  319.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  320.                 RGBForeColor(&oldcolor);
  321.             } else if (timg->patdefined) {
  322.                 /* Fall back on the b/w pattern. */
  323. #ifdef THINK_C
  324.                 FillPoly(poly, (Pattern *) &(timg->pat));
  325. #endif
  326.             }
  327.         } else {
  328. #ifdef THINK_C
  329.             FillPoly(poly, (Pattern *) &(timg->pat));
  330. #endif
  331.         }
  332.         /* Darken the cell. */
  333.         if (t2 == -1) {
  334.             PenPat(QD(gray));
  335. /*            PenMode(patBic);  */
  336.             PenMode(notPatOr);
  337.             PaintPoly(poly);
  338.             PenNormal();
  339.         }
  340.     }
  341. }
  342.  
  343. draw_hex_region(sx, sy, power, dogrid, t, t2)
  344. int sx, sy, power, dogrid, t, t2;
  345. {
  346.     Image *timg;
  347.     RGBColor hexcolor, oldcolor;
  348.     RgnHandle rgn;
  349.  
  350.     if (bestterrainimages == NULL) {
  351.         calc_best_terrain_images();
  352.     }
  353.     timg = bestterrainimages[power * numttypes + t];
  354.     if (timg) {
  355.         move_cell_region(sx, sy, power);
  356.         rgn = (dogrid ? gridcellrgns[power] : cellrgns[power]);
  357.         if (hasColorQD) {
  358.             if (timg->colrpat != nil
  359.                 && (minscreendepth > 1 || !timg->patdefined)) {
  360.                 FillCRgn(rgn, timg->colrpat);
  361.             } else if (tcolors[t] != NULL && maxscreendepth > 1) {
  362.                 hexcolor.red   = (tcolors[t]->r) << 8;
  363.                 hexcolor.green = (tcolors[t]->g) << 8;
  364.                 hexcolor.blue  = (tcolors[t]->b) << 8;
  365.                 RGBForeColor(&hexcolor);
  366.                 PaintRgn(rgn);
  367.                 /* Restore the previous color. */
  368.                 oldcolor.red = oldcolor.green = oldcolor.blue = 0;
  369.                 RGBForeColor(&oldcolor);
  370.             } else if (timg->patdefined) {
  371.                 /* Fall back on the b/w pattern. */
  372. #ifdef THINK_C
  373.                 FillRgn(rgn, (Pattern *) &(timg->pat));
  374. #endif
  375.             }
  376.         } else {
  377. #ifdef THINK_C
  378.             FillRgn(rgn, (Pattern *) &(timg->pat));
  379. #endif
  380.         }
  381.         /* Darken the cell. */
  382.         if (t2 == -1) {
  383.             PenPat(QD(gray));
  384. /*            PenMode(patBic);  */
  385.             PenMode(notPatOr);
  386.             PaintRgn(rgn);
  387.             PenNormal();
  388.         }
  389.     }
  390. }
  391.  
  392. /* Draw a set of borders for the given hex. */
  393.  
  394. draw_border_line_multiple(win, sx, sy, bitmask, power, t)
  395. WindowPtr win;
  396. int sx, sy, bitmask, power, t;
  397. {
  398.     int wid = bwid[power], wid2, dir;
  399.     Image *timg;
  400.  
  401.     if (wid == 0) return;
  402.     wid2 = wid / 2;
  403.     if (0 /* power == 4*/) {
  404.         Rect srcrect, destrect;
  405.         BitMap *winbits;
  406.  
  407.         winbits = &(((GrafPtr) win)->portBits);
  408.         SetRect(&srcrect, 0, 0, 32, 32);
  409.         SetRect(&destrect, sx, sy, sx+32, sy+32);
  410.         CopyBits(&(bordbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
  411.         return;
  412.     }
  413.     PenSize(wid, wid);
  414.     /* Decide on the line color/pattern to use. */
  415.     timg = best_image(&(timages[t]), wid, wid);
  416.     for_all_directions(dir) {
  417.         if (bitmask & (1 << dir)) {
  418.             if (timg) {
  419.                 if (hasColorQD) {
  420.                     if (timg->colrpat && (maxscreendepth > 1 || !timg->patdefined)) {
  421.                         PenPixPat(timg->colrpat);
  422.                     } else {
  423. #ifdef THINK_C
  424.                         PenPat((Pattern *) &(timg->pat));
  425. #endif
  426.                     }
  427.                 } else {
  428. #ifdef THINK_C
  429.                     PenPat((Pattern *) &(timg->pat));
  430. #endif
  431.                 }
  432.             } else {
  433.                 PenPat(QD(dkGray));
  434.             }
  435.             /* Actually draw the line. */
  436.             MoveTo(sx + bsx[power][dir] - wid2, sy + bsy[power][dir] - wid2);
  437.             LineTo(sx + bsx[power][dir+1] - wid2, sy + bsy[power][dir+1] - wid2);
  438.         }
  439.     }
  440.     PenNormal();
  441. }
  442.  
  443. /* Draw a set of connections for the given ttype and given hex. */
  444.  
  445. draw_connection_line_multiple(win, sx, sy, bitmask, power, t)
  446. WindowPtr win;
  447. int sx, sy, bitmask, power, t;
  448. {
  449.     int dir, wid = cwid[power];
  450.     Image *timg;
  451.  
  452.     if (wid == 0) return;
  453.     if (0 /*power == 4*/) {
  454.         Rect srcrect, destrect;
  455.         BitMap *winbits;
  456.  
  457.         winbits = &(((GrafPtr) win)->portBits);
  458.         SetRect(&srcrect, 0, 0, 32, 32);
  459.         SetRect(&destrect, sx, sy, sx+32, sy+32);
  460.         CopyBits(&(connbitmaps[4]), winbits, &srcrect, &destrect, srcOr, nil);
  461.         return;
  462.     }
  463.     PenSize(wid, wid);
  464.     timg = best_image(&(timages[t]), wid, wid);
  465.     for_all_directions(dir) {
  466.         if (bitmask & (1 << dir)) {
  467.             if (timg) {
  468.                 if (hasColorQD) {
  469.                     if (timg->colrpat && (maxscreendepth > 1 || !timg->patdefined)) {
  470.                         PenPixPat(timg->colrpat);
  471.                     } else {
  472. #ifdef THINK_C
  473.                         PenPat((Pattern *) &(timg->pat));
  474. #endif
  475.                     }
  476.                 } else {
  477. #ifdef THINK_C
  478.                     PenPat((Pattern *) &(timg->pat));
  479. #endif
  480.                 }
  481.             } else {
  482.                 PenPat(QD(gray));
  483.             }
  484.             MoveTo(sx + hws[power] / 2 - wid / 2, sy + hhs[power] / 2 - wid / 2);
  485.             Line(lsx[power][dir], lsy[power][dir]);
  486.         }
  487.     }
  488.     PenNormal();
  489. }
  490.  
  491. /* This draws a type of terrain in a way that indicates its subtype. */
  492.  
  493. draw_terrain_sample(tmprect, t)
  494. Rect tmprect;
  495. int t;
  496. {
  497.     int dir;
  498.  
  499.     switch (t_subtype(t)) {
  500.         case cellsubtype:
  501.             draw_hex_polygon(tmprect.left, tmprect.top, 4, FALSE, t, 0);
  502.             break;
  503.         case bordersubtype:
  504.             draw_border_line_multiple(designwin, tmprect.left, tmprect.top, -1, 4, t);
  505.             break;
  506.         case connectionsubtype:
  507.             draw_connection_line_multiple(designwin, tmprect.left, tmprect.top, -1, 4, t);
  508.             break;
  509.         case coatingsubtype:
  510.             draw_hex_polygon(tmprect.left, tmprect.top, 4, FALSE, t, 0);
  511.             /* Make it a 50% pattern. (should make more obvious somehow?) */
  512.             gray_out_rect(&tmprect);
  513.             break;
  514.         default:
  515.             terrain_subtype_warning("draw sample", t);
  516.             break;
  517.     }
  518. }
  519.  
  520. /* Draw a set of country border at the given position. */
  521.  
  522. draw_country_borders(win, sx, sy, bitmask, power, shade)
  523. WindowPtr win;
  524. int sx, sy, bitmask, power, shade;
  525. {
  526.     int wid = bwid2[power], wid2, dir;
  527.  
  528.     if (wid == 0) return;
  529.     PenSize(wid, wid);
  530.     if (shade == 0) PenPat(QD(black));
  531.     if (shade == 2) PenPat(QD(gray));
  532.     wid2 = wid / 2;
  533.     for_all_directions(dir) {
  534.         if (bitmask & (1 << dir)) {
  535.             MoveTo(sx + bsx[power][dir] - wid2, sy + bsy[power][dir] - wid2);
  536.             LineTo(sx + bsx[power][dir+1] - wid2, sy + bsy[power][dir+1] - wid2);
  537.         }
  538.     }
  539.     PenNormal();
  540. }
  541.  
  542. /* Draw a set of theater borders at the given position. */
  543.  
  544. draw_theater_borders(win, sx, sy, bitmask, power)
  545. WindowPtr win;
  546. int sx, sy, bitmask, power;
  547. {
  548.     int wid, wid2, dir;
  549.     Rect tmprect;
  550.  
  551.     if (bwid[power] > 0) {
  552.         wid = 2;
  553.         PenSize(wid, wid);
  554.         PenMode(notPatCopy);
  555.         wid2 = wid / 2;
  556.         for_all_directions(dir) {
  557.             if (bitmask & (1 << dir)) {
  558.                 MoveTo(sx + bsx[power][dir] - wid2, sy + bsy[power][dir] - wid2);
  559.                 LineTo(sx + bsx[power][dir+1] - wid2, sy + bsy[power][dir+1] - wid2);
  560.             }
  561.         }
  562.         PenNormal();
  563.     } else {
  564.         SetRect(&tmprect, sx, sy, sx + hws[power], sy + hhs[power]);
  565.         FillRect(&tmprect, QD(white));
  566.     }
  567. }
  568.  
  569. /* Indicate the elevation of the given location, textually for now. */
  570.  
  571. draw_elevation(sx, sy, power, elev)
  572. int sx, sy, power, elev;
  573. {
  574.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  575.     if (elev != 0) {
  576.         sprintf(spbuf, "%d", elev);
  577.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  578.     }
  579.     /* (Also draw contour lines eventually) */
  580. }
  581.  
  582. /* Don't draw the temperature in every hex, only do ones with even coords or
  583.    ones where the temperature in any adjacent cell is different. */
  584.  
  585. draw_temperature_here(x, y)
  586. int x, y;
  587. {
  588.     int dir, x1, y1, temphere = temperature_at(x, y);
  589.  
  590.     if (dside->designer) return TRUE;
  591.     if (!g_see_all() && cover(dside, x, y) == 0) return FALSE;
  592.     for_all_directions(dir) {
  593.         point_in_dir(x, y, dir, &x1, &y1);
  594.         if (temphere != temperature_at(x1, y1)) {
  595.             return TRUE;
  596.         }
  597.     }
  598.     return (x % 2 == 0 && y % 2 == 0);
  599. }
  600.  
  601. /* Indicate the temperature of the given location, textually for now. */
  602.  
  603. draw_temperature(sx, sy, power, temp)
  604. int sx, sy, power, temp;
  605. {
  606.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  607.     if (1 /* temp != 0 */) {
  608.         sprintf(spbuf, "%d°", temp);  /* (should do char more portably) */
  609.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  610.     }
  611.     /* (Also draw isotherms eventually) */
  612. }
  613.  
  614. /* Don't draw the winds in every hex, only do ones with odd coords or
  615.    ones where the wind in any adjacent cell is different. */
  616.  
  617. draw_winds_here(x, y)
  618. int x, y;
  619. {
  620.     int dir, x1, y1, windhere = raw_wind_at(x, y);
  621.  
  622.     if (dside->designer) return TRUE;
  623.     if (!g_see_all() && cover(dside, x, y) == 0) return FALSE;
  624.     for_all_directions(dir) {
  625.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  626.             if (windhere != raw_wind_at(x1, y1)) {
  627.                 return TRUE;
  628.             }
  629.         }
  630.     }
  631.     return (x % 2 == 1 && y % 2 == 1);
  632. }
  633.  
  634. draw_clouds_here(x, y)
  635. int x, y;
  636. {
  637.     int dir, x1, y1, cloudhere = raw_cloud_at(x, y);
  638.  
  639.     if (dside->designer) return TRUE;
  640.     if (!g_see_all() && cover(dside, x, y) == 0) return FALSE;
  641.     return TRUE;
  642. }
  643.  
  644.  
  645. /* Indicate the winds at the given location. */
  646.  
  647. draw_winds(sx, sy, power, wdir, wforce)
  648. int sx, sy, power, wdir, wforce;
  649. {
  650.     GrafPtr curport;
  651.  
  652.     if (wforce > 0) {
  653.         sx += (hws[power] - 16) / 2;  sy += (hhs[power] - 16) / 2;
  654.         if (wforce > 4) wforce = 4;
  655.         if (numwindsicns == 0) {
  656.             int i;
  657.  
  658.             for (i = 1; i <= 4; ++i) {
  659.                 windsicnhandle[i] = GetResource('SICN', sicnWinds1 + i - 1);
  660.             }
  661.             numwindsicns = 4;
  662.         }
  663.         GetPort(&curport);
  664.         plot_sicn(curport, sx, sy, windsicnhandle[wforce], wdir, FALSE);
  665.     } else {
  666.         sx += hws[power] / 2;  sy += hhs[power] / 2;
  667.         sprintf(spbuf, "Calm");
  668.         draw_legend_text(sx, sy, hhs[power] / 2, spbuf, 0);
  669.     }
  670. }
  671.  
  672. draw_clouds(sx, sy, power, cloudtype)
  673. int sx, sy, power, cloudtype;
  674. {
  675.     Rect tmprect;
  676.  
  677.     if (cloudtype == 0) return;
  678.     sx += hws[power] / 2;  sy += hhs[power] / 2;
  679.     SetRect(&tmprect, sx - hws[power] / 2, sy - hhs[power] / 2, sx + hws[power] / 2, sy + hhs[power] / 2);
  680.     /* Should use pat# 130 patterns for this instead. */
  681.     PenPat(cloudtype == 3 ? QD(dkGray) : (cloudtype == 2 ? QD(gray) : QD(ltGray)));
  682.     PenMode(patBic);
  683.     PaintOval(&tmprect);
  684.     PenNormal();
  685. }
  686.  
  687. /* Draw the number of units observing a cell (for debugging). */
  688.  
  689. draw_coverage(sx, sy, power, cov)
  690. int sx, sy, power, cov;
  691. {
  692.     sx += 2;  sy += hhs[power] - hcs[power] - 10;
  693.     sprintf(spbuf, ":%d:", cov);
  694.     draw_legend_text(sx, sy, hhs[power] / 2, spbuf, -1);
  695. }
  696.  
  697. /* Draw a unit's name or number. */
  698.  
  699. draw_unit_name(unit, sx, sy, sw, sh)
  700. Unit *unit;
  701. int sx, sy, sw, sh;
  702. {
  703.     char legend[BUFSIZE];
  704.  
  705.     name_or_number(unit, legend);
  706.     if (strlen(legend) > 0) {
  707.         draw_legend_text(sx + sw + 1, sy + sh/2, sh, legend, -1);
  708.     }
  709. }
  710.  
  711. draw_legend_text(sx, sy, sh, legend, just)
  712. int sx, sy, sh, just;
  713. char *legend;
  714. {
  715.     int strwid, strleft;
  716.     Rect maskrect;
  717.     FontInfo fontinfo;
  718.     Str255 tmpstr;
  719.     
  720.     /* Scale text sizes to fit in smaller cells if necessary. */
  721.     TextSize(min(max(5, sh), 10));
  722.     strwid = TextWidth(legend, 0, strlen(legend));
  723.     if (just < 0) {
  724.         strleft = sx;
  725.     } else if (just > 0) {
  726.         strleft = sx - strwid;
  727.     } else {
  728.         strleft = sx - strwid / 2;
  729.     }
  730.     MoveTo(strleft, sy);
  731.     if (0) {
  732.         /* Make it readable against a noisy background. */
  733. /*        TextFace(bold|outline); */
  734.         TextMode(srcBic);
  735.     } else {
  736.         /* This makes a big white box for name, less attractive but easier to read. */
  737.         GetFontInfo(&fontinfo);
  738.         maskrect.top = sy - fontinfo.ascent - 1;  /* this seems to be too much? */
  739.         maskrect.top += 3;
  740.         maskrect.left = strleft - 1;
  741.         maskrect.bottom = sy + fontinfo.descent;
  742.         maskrect.right = maskrect.left + strwid + 1;
  743.         FillRect(&maskrect, QD(white));
  744.     }
  745.     DrawText(legend, 0, strlen(legend));
  746. }
  747.  
  748. draw_blast_image(win, sx, sy, sw, sh, blasttype)
  749. WindowPtr win;
  750. int sx, sy, sw, sh, blasttype;
  751. {
  752.     long startcount;
  753.     Rect tmprect;
  754.     Handle sound;
  755.     extern int numsoundplays;
  756.     extern int playsounds;
  757.  
  758.     SetRect(&tmprect, sx, sy, sx + sw, sy + sh);
  759.     if (playsounds && numsoundplays < 1) {
  760.         if (0 /* certain games */) {
  761.             sound = GetNamedResource('snd ', "\plaser");
  762.         } else {
  763.             sound = GetNamedResource('snd ', "\pcrunch");
  764.         }
  765.         if (sound != nil) {
  766.             SndPlay(nil, sound, false);
  767.             ReleaseResource(sound);
  768.         }
  769.         ++numsoundplays;
  770.     }
  771.     if (1) {
  772.         if (sw >= 16) {
  773.             /* Instead should save image under here, then draw blast */
  774.             InvertRect(&tmprect);
  775.         } else {
  776.             InvertRect(&tmprect);
  777.         }
  778.         startcount = TickCount();
  779.         if (playsounds) {
  780.             if (blasttype > 1) {
  781.                 sound = GetNamedResource('snd ', "\pboom");
  782.             } else if (blasttype > 0) {
  783.                 sound = GetNamedResource('snd ', "\pboom");
  784.             } else {
  785.                 sound = nil;
  786.             }
  787.             if (sound != nil) {
  788.                 SndPlay(nil, sound, false);
  789.                 ReleaseResource(sound);
  790.             }
  791.         } else {
  792.             /* Delay for part of a second (should relinquish cpu tho) */
  793.             while ((TickCount() - startcount) < (blasttype > 1 ? 27 : (blasttype > 0 ? 9 : 3)));
  794.         }
  795.         if (sw >= 16) {
  796.             /* Instead should restore image under here */
  797.             InvertRect(&tmprect);
  798.         } else {
  799.             InvertRect(&tmprect);
  800.         }
  801.     }
  802. }
  803.  
  804. picture_width(pichandle)
  805. PicHandle pichandle;
  806. {
  807.     return ((*pichandle)->picFrame.right - (*pichandle)->picFrame.left);
  808. }
  809.  
  810. picture_height(pichandle)
  811. PicHandle pichandle;
  812. {
  813.     return ((*pichandle)->picFrame.bottom - (*pichandle)->picFrame.top);
  814. }
  815.  
  816. /* Generic sicn drawer. */
  817.  
  818. plot_sicn(win, sx, sy, sicnhandle, n, erase)
  819. WindowPtr win;
  820. int sx, sy, n, erase;
  821. Handle sicnhandle;
  822. {
  823.     Rect srcrect, imagerect;
  824.     RgnHandle tmprgn;
  825.     BitMap bm, *winbits;
  826.  
  827.     if (sicnhandle == nil) return;
  828.     imagerect = win->portRect;
  829.     imagerect.left += sx;  imagerect.top += sy;
  830.     imagerect.right = imagerect.left + 16;  imagerect.bottom = imagerect.top + 16;
  831.     winbits = &(((GrafPtr) win)->portBits);
  832.     SetRect(&srcrect, 0, 0, 16, 16);
  833.     bm.rowBytes = 2;
  834.     bm.bounds = srcrect;
  835.     if (erase) EraseRect(&imagerect);
  836.     bm.baseAddr = *(sicnhandle) + 32 * n;
  837.     CopyBits(&bm, winbits, &srcrect, &imagerect, srcOr, nil);
  838. }
  839.  
  840. /* Given a rectangle, make half of its pixels white. */
  841.  
  842. gray_out_rect(rectptr)
  843. Rect *rectptr;
  844. {
  845.     PenPat(QD(gray));
  846.     PenMode(patBic);
  847.     PaintRect(rectptr);
  848.     PenNormal();
  849. }
  850.